package itsm.isperp.framework.service;

import itsm.isperp.framework.collection.map.LowercaseKeyHashMap;
import itsm.isperp.framework.data.commons.repository.BaseRepository;
import itsm.isperp.framework.data.domain.DataRequest;
import itsm.isperp.framework.data.domain.DataResponse;
import itsm.isperp.framework.data.domain.QueryFilter;
import itsm.isperp.framework.domain.IBean;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.web.domain.CountQuery;
import itsm.isperp.framework.web.request.DefaultCountQuery;
import itsm.isperp.framework.web.request.JqGridFilterRuleOp;
import itsm.isperp.framework.web.request.JqGridRequest;
import itsm.isperp.framework.web.response.ResultMessage;

import java.lang.reflect.ParameterizedType;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Table;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

/**
 * 基础业务抽象类.是一般实体bean的业务基础服务.
 * 
 * @see IBaseService
 * @author lizx
 * @date 2012-6-22
 * @since 1.0
 */
public abstract class BaseService<T extends IBean> implements IBaseService<T> {

	/**
	 * 返回一个具有基础数据操作功能的访问接口
	 * 
	 * @see BaseRepository
	 * @return 数据仓库访问接口
	 */
	public abstract BaseRepository<T> getRepository();

	public CountQuery createDefaultCountQuery() {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		Table table = clazz.getAnnotation(Table.class);
		CountQuery cq = new DefaultCountQuery(table.name());
		return cq;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#saveOrUpdate(itsm.isperp.framework
	 * .domain.IBean)
	 */
	@Override
	public <S extends T> int saveOrUpdate(S entity) {

		if (StringUtils.isEmpty(entity.getId())) {
			entity.setId(HibernateUUIDGenerator.generate());
			return this.getRepository().save(entity);
		} else {
			if (this.getRepository().existsByClass(entity.getId(),
					entity.getClass()) == null) {
				return this.getRepository().save(entity);
			} else {
				this.getRepository().update(entity);

			}

			return 1;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.IBaseService#saveOrUpdateButSpecific
	 * (itsm.isperp.framework.domain.IBean, java.util.Set)
	 */
	@Override
	public <S extends T> int saveOrUpdateButSpecific(S entity,
			Set<String> unIncludeColumns) {

		if (StringUtils.isEmpty(entity.getId())) {
			entity.setId(HibernateUUIDGenerator.generate());

			return this.getRepository().save(entity);
		} else {

			if (this.getRepository().existsByClass(entity.getId(),
					entity.getClass()) == null) {

				return this.getRepository().save(entity);
			} else {

				this.getRepository().dynamicButSpecificUpdate(entity,
						unIncludeColumns);

			}
			return 1;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#saveOrUpdateSpecific(itsm.
	 * isperp.framework .domain.IBean, java.util.Set)
	 */
	@Override
	public <S extends T> int saveOrUpdateSpecific(S entity,
			Set<String> includeColumns) {
		Assert.notNull(entity, "对象不能为空");

		// System.out.println(includeColumns.toString());

		if (StringUtils.isEmpty(entity.getId())) {
			entity.setId(HibernateUUIDGenerator.generate());

			this.getRepository().dynamicSpecificSave(entity, includeColumns);
			return 1;
		} else {
			if (this.getRepository().existsByClass(entity.getId(),
					entity.getClass()) == null) {

				this.getRepository()
						.dynamicSpecificSave(entity, includeColumns);
				return 1;
			} else {

				this.getRepository().dynamicSpecificUpdate(entity,
						includeColumns);
			}

			return 1;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#saveOrUpdate(itsm.isperp.framework
	 * .domain.IBean, javax.servlet.http.HttpServletRequest)
	 */
	@Override
	public <S extends T> int saveOrUpdate(S entity, HttpServletRequest req) {
		Assert.notNull(entity, "对象不能为空");

		return this.saveOrUpdateAndSpecific(entity, req);
	}

	@Override
	public <S extends T> int saveOrUpdate(S entity, HttpServletRequest req,
			String... otherFields) {
		Assert.notNull(entity, "对象不能为空");

		return this.saveOrUpdateAndSpecific(entity, req, otherFields);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#saveOrUpdateAndSpecific(itsm
	 * .isperp.framework.domain.IBean, javax.servlet.http.HttpServletRequest,
	 * java.lang.String[])
	 */
	@Override
	public <S extends T> int saveOrUpdateAndSpecific(S entity,
			HttpServletRequest req, String... otherFields) {

		Enumeration<String> params = req.getParameterNames();

		Set<String> includeColumns = new HashSet<String>();

		for (; params.hasMoreElements();) {
			String v = params.nextElement();
			if (v.charAt(0) == '_') {
				v = v.substring(1);
			}
			includeColumns.add(v);
		}

		if (otherFields != null) {
			for (String s : otherFields) {
				if (!includeColumns.contains(s))
					includeColumns.add(s);
			}
		}

		return this.saveOrUpdateSpecific(entity, includeColumns);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.IBaseService#findOne(java.lang.String)
	 */
	@Override
	public T findOne(String id) {

		return StringUtils.isEmpty(id) ? null : this.getRepository()
				.findOne(id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.IBaseService#exists(java.lang.String)
	 */
	public boolean exists(String id) {
		if (StringUtils.isEmpty(id))
			return false;
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return this.getRepository().existsByClass(id, clazz) != null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#findAll(itsm.isperp.framework
	 * .web.domain.DataRequest)
	 */
	public DataResponse<T> findAll(DataRequest req) {

		// @SuppressWarnings("unchecked")
		// Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
		// .getGenericSuperclass()).getActualTypeArguments()[0];
		// add sort
		// try {
		// if (req.getSort() == null
		// && clazz.getDeclaredField("orderNum") != null) {
		// req.setSort("order_num", Direction.ASC);
		// }
		// } catch (Exception e) {
		//
		// }

		return this.getRepository().findAllByRequest(req);
	}

	public DataResponse<T> findAll() {
		JqGridRequest req = new JqGridRequest();
		req.isPageable(false);
		return this.getRepository().findAllByRequest(req);
	}

	public Long findAllCount(QueryFilter filter) {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		return this.getRepository().findAllCount(clazz, filter);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.IBaseService#delete(java.lang.String)
	 */
	public ResultMessage delete(String id) {
		Assert.notNull(id, "id不能为空");
		// 利用泛型获取class
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		this.getRepository().deleteByClass(id, clazz);

		return ResultMessage.success();

	}

	public void deleteAll() {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		this.getRepository().deleteAll(clazz);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#dynamicButSpecificUpdate(itsm
	 * .isperp.framework.domain.IBean, java.util.Set)
	 */
	public <S extends T> void dynamicButSpecificUpdate(S entity,
			Set<String> unIncludeColumns) {
		Assert.notNull(entity, "对象不能为空");
		this.getRepository().dynamicButSpecificUpdate(entity, unIncludeColumns);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#dynamicUpdateSpecific(itsm
	 * .isperp.framework.domain.IBean, java.util.Set)
	 */
	public <S extends T> void dynamicUpdateSpecific(S entity,
			Set<String> includeColumns) {
		Assert.notNull(entity, "对象不能为空");
		this.getRepository().dynamicSpecificUpdate(entity, includeColumns);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * itsm.isperp.framework.service.IBaseService#findOneToMap(java.lang.String)
	 */
	public Map<String, Object> findOneToMap(String id) {
		Assert.notNull(id, "id不能为空");

		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return this.getRepository().findOneByClass(id, clazz);
	}

	public Map<String, Object> findOneToMap(String id, String... selectColumns) {
		if (StringUtils.isEmpty(id)) {
			return null;
		}

		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return this.getRepository().findOneByClassAndColumns(id, clazz,
				selectColumns);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see itsm.isperp.framework.service.IBaseService#findAllToMap()
	 */
	public List<LowercaseKeyHashMap<String, Object>> findAllToMap() {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return this.getRepository().findAllByClass(clazz);
	}

	public List<LowercaseKeyHashMap<String, Object>> findAllToMap(
			QueryFilter filter) {
		@SuppressWarnings("unchecked")
		Class<T> clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];

		return this.getRepository().findAllByClassAndFilter(clazz, filter);
	}

	/*
	 * 
	 */
	public Map<String, Object> findOneDetailById(String id) {
		JqGridRequest req = new JqGridRequest();
		req.isPageable(false);
		req.isQueryOne(true);
		req.addFilterRule("id", JqGridFilterRuleOp.eq, id);
		DataResponse<Map<String, Object>> result = this
				.findAllDetailByRequest(req);
		if (result == null || result.isEmpty()) {
			return null;
		}
		return result.get(0);

	}

	public DataResponse<Map<String, Object>> findAllDetailByRequest(
			DataRequest request) {
		return this.getRepository().findAllDetailByRequest(request);

	}

	public Map<String, Object> findOneDetailByRequest(DataRequest request) {
		request.isPageable(false);
		request.setRows(1);
		List<Map<String, Object>> list = this.findAllDetailByRequest(request);
		if (list != null && list.size() == 1) {
			return list.get(0);
		}
		return null;
	}

	public T findOneByRequest(DataRequest request) {
		request.isPageable(false);
		request.isQueryOne(true);
		request.setRows(1);
		List<T> list = this.findAll(request);
		if (list != null && list.size() == 1) {
			return list.get(0);
		}
		return null;
	}

}
